use std::fmt;

#[derive(Debug, Clone)]
pub enum AllocEvent {
    RequestAlloc {
        size: usize,
    },
    AllocSuccess {
        ptr: usize,
        size: usize,
        page_id: usize,
    },
    AllocFail {
        size: usize,
    },
    RequestFree {
        ptr: usize,
    },
    FreeSuccess {
        ptr: usize,
        page_id: usize,
    },
    FreeFail {
        ptr: usize,
    },
    PageCreate {
        page_id: usize,
        block_size: usize,
    },
    PageFull {
        page_id: usize,
    },
}

pub struct Logger {
    events: Vec<(usize, AllocEvent)>,
    current_time: usize,
}

impl Logger {
    pub fn new() -> Self {
        Logger {
            events: Vec::new(),
            current_time: 0,
        }
    }

    pub fn log(&mut self, event: AllocEvent) {
        println!("t={}: {:?}", self.current_time, event);
        self.events.push((self.current_time, event));
        self.current_time += 1;
    }

    pub fn dump(&self) -> String {
        let mut output = String::new();
        for (time, event) in &self.events {
            output.push_str(&format!("t={}: {:?}\n", time, event));
        }
        output
    }

    pub fn reset(&mut self) {
        self.events.clear();
        self.current_time = 0;
    }
}

impl fmt::Debug for Logger {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.dump())
    }
}
